<?php
require_once('pworks/util/ClassLoader.class.php');
require_once('pworks/db/XMLConfigLoader.class.php');

class DaoFactory {

    private static $_connections;

    private static $_daos;

    private static $_cache;

    private static $_useCache=false;

    private static $_cacheVarPrefix;

    private static $_dsConfigs;

    private static $_daoConfigs;

    private static $factory_id = 'adsfk2901274djs8293y45hg7dtsarf23r9';

    public static function dump(){
        DebugUtil::dump(self::$_connections, __FILE__, __LINE__);
        DebugUtil::dump(self::$_daos, __FILE__, __LINE__);
        DebugUtil::dump(self::$_cache, __FILE__, __LINE__);
        DebugUtil::dump(self::$_useCache, __FILE__, __LINE__);
        DebugUtil::dump(self::$_cacheVarPrefix, __FILE__, __LINE__);
        DebugUtil::dump(self::$_dsConfigs, __FILE__, __LINE__);
        DebugUtil::dump(self::$_daoConfigs, __FILE__, __LINE__);
    }

    public static function getDao($daoName) {
        if(array_key_exists($daoName, self::$_daos)){
            return self::$_daos[$daoName];
        }else{
            if(array_key_exists($daoName, self::$_daoConfigs)){
                $daoCfg = self::$_daoConfigs[$daoName];
                try
                {
                    ClassLoader::isClassExist($daoCfg->clzName, $daoCfg->src);
                }catch(SystemException $e){
                    $e->message = $e->getMessage() . '[in'.__FILE__.', line:'.__LINE__.' ]';
                    throw $e;
                }

                $conn = self::getConnection($daoCfg->ds);

                if(self::$_useCache && self::$_cache!=null){
                    $cacheVarName = self::$_cacheVarPrefix . "_daos_" . $daoName;
                    $dao = self::$_cache->fetch($cacheVarName);
                    if($dao){
                        self::$_daos[$daoName] = $dao;
                        $dao->setConnection($conn);
                        return $dao;
                    }
                }
                
                $dao = null;
                try{
                    $dao = ClassLoader::getInstance($daoCfg->clzName, $daoCfg->src);
                }catch(SystemException $e){
                    $e->message = $e->getMessage() . '[in'.__FILE__.', line:'.__LINE__.' ]';
                    throw $e;
                }
                $dao->setConnection($conn);
                if(self::$_useCache && self::$_cache!=null){
                    $cacheVarName = self::$_cacheVarPrefix . "_daos_" . $daoName;
                    self::$_cache->fetch($cacheVarName, $dao);
                }

                self::$_daos[$daoName] = $dao;
                return $dao;
            }else{
                throw new SystemException(SystemException::DAO_ERROR, 'Specific DAO ' . $daoName . ' is not defined');
            }
        }
        return null;
    }

    private static function getConnection($dsId){
        //DebugUtil::dump(self::$_connections, __FILE__, __LINE__);
        if(array_key_exists($dsId, self::$_connections)){
            $conn = self::$_connections[$dsId];
            return $conn;
        }else{
            /*if(self::$_useCache && self::$_cache!=null){
                $cacheVarName = self::$_cacheVarPrefix . "_conns_" . $dsId;
                $conn = self::$_cache->fetch($cacheVarName);
                if($conn){
                    self::$_connections[$dsId] = $conn;
                    return $conn;
                }
            }*/

            //DebugUtil::dump($dsId, __FILE__, __LINE__);
            //DebugUtil::dump(self::$_dsConfigs, __FILE__, __LINE__);
            if(array_key_exists($dsId, self::$_dsConfigs)){
                $dsCfg = self::$_dsConfigs[$dsId];
                $conn = new mysqli($dsCfg->host
                                , $dsCfg->user
                                , $dsCfg->password
                                , $dsCfg->db);
                if(mysqli_connect_errno()){
                    throw new SystemException(SystemException::DB_ERROR, mysqli_connect_error());
                }else{
                    if(!$conn->set_charset($dsCfg->charset)){
                        throw new SystemException(SystemException::DB_ERROR, $conn->error);
                    }
                }

/*                if(self::$_useCache && self::$_cache!=null){
                    $cacheVarName = self::$_cacheVarPrefix . "_conns_" . $dsId;
                    self::$_cache->store($cacheVarName, $conn);
                }*/

                self::$_connections[$dsId] = $conn;
                return $conn;
            }

            throw new SystemException(SystemException::DB_ERROR, 'No DB connection  matchs datasource ' . $dsId);
        }
        return null;
    }


    public static function config($configFile) {
        if(self::loadCachedCfg()) return;

        $loader = new XMLConfigLoader();
        $loader->load($configFile);
        self::$_dsConfigs = $loader->getDsConfigs();
        self::$_daoConfigs = $loader->getDaoConfigs();
        self::$_connections = array();
        self::$_daos = array();

        self::cacheConfig();
    }

    private static function loadCachedCfg(){
        if(self::$_useCache && self::$_cache!=null){
            $cacheFlag = self::$_cache->fetch(self::$_cacheVarPrefix .'_cache_flag');
            if($cacheFlag){
                self::$_dsConfigs = self::$_cache->fetch(self::$_cacheVarPrefix .'_dsconfigs');
                self::$_daoConfigs = self::$_cache->fetch(self::$_cacheVarPrefix .'_daoconfigs');
                self::$_connections = array();
                self::$_daos = array();
                return true;
            }
        }
        return false;
    }

    private static function cacheConfig(){
        if(self::$_useCache && self::$_cache!=null){
//DebugUtil::dump(self::$_dsConfigs, __FILE__, __LINE__);
//DebugUtil::dump(self::$_daoConfigs, __FILE__, __LINE__);
//DebugUtil::dump(self::$_cache, __FILE__, __LINE__);

            self::$_cache->store(self::$_cacheVarPrefix .'_dsconfigs', new ArrayObject(self::$_dsConfigs));
            self::$_cache->store(self::$_cacheVarPrefix .'_daoconfigs', new ArrayObject(self::$_daoConfigs));
            self::$_cache->store(self::$_cacheVarPrefix .'_cache_flag', true);
//echo '<hr>';
//DebugUtil::dump(apc_sma_info(), __FILE__, __LINE__);
//echo '<hr>';            
        }
    }

    public static function setCache(ICache $cache, $prefix=null) {
        if($cache == null){
            self::$_cache = null;
            self::$_useCache = false;
        }else{
            self::$_cache = $cache;
            self::$_useCache = true;
            if($prefix != null){
                self::$_cacheVarPrefix = $prefix;
            }else{
                self::$_cacheVarPrefix = self::$factory_id;
            }
        }
    }
}
?>
